local japi = require 'jass.japi'
local runtime = require 'jass.runtime'
local KEY = KEY

local hardware = {}
ac.hardware = hardware

hardware.alltriggers = {}
hardware.allacts = setmetatable({}, {__mode = 'kv'})
hardware.clock = os.clock()

--[获取屏幕鼠标坐标]
function hardware:get_mouse_pos()
    local x = japi.GetMouseVectorX() / 1024
    local y = (-(japi.GetMouseVectorY() - 768)) / 768
    x = x * 1920
    y = y * 1080
    return x,y
end

--[设置屏幕鼠标坐标]
function hardware:set_mouse_pos(x,y)
    x = x / 1920 * 1024
    y = 768 - y / 1080 * 768
    japi.SetMousePos(x,y)
end

--[鼠标左键按下]
function hardware.on_mouse_down()
    return hardware.notify('鼠标点击')
end

--[鼠标左键弹起]
function hardware.on_mouse_up()
    return hardware.notify('鼠标释放')
end

--[鼠标右键按下]
function hardware.on_mouse_right_down()
    return hardware.notify('鼠标右键点击')
end

--[鼠标右键弹起]
function hardware.on_mouse_right_up()
    return hardware.notify('鼠标右键释放')
end

--[滚轮滚动事件]
function hardware.on_mouse_wheeldelta()
    return hardware.notify('鼠标滑轮滚动', japi.GetWheelDelta() > 0)
end

--[键盘按下事件]
function hardware.on_key_down()
    local code = japi.GetTriggerKey()
    local skey = KEY[code] or code
    return hardware.notify('键盘按下', skey)
end

--[键盘弹起事件]
function hardware.on_key_up()
    local code = japi.GetTriggerKey()
    local skey = KEY[code] or code
    return hardware.notify('键盘弹起', skey)
end

--[窗口更新大小事件]
function hardware.on_update_window_size()
    return hardware.notify('窗口大小刷新')
end

--[指向物体更新]
function hardware.on_widget_update()
    -- if not package.load_step or package.load_step == 0 then return false end;
    -- local new_widget = japi.GetTargetObject()
    -- local old_widget = hardware._widget or 0
    -- if japi.IsWindowActive() then
    --     if new_widget == 0 then
    --         if old_widget ~= 0 then 
    --             hardware.notify('鼠标离开物体', old_widget)
    --             hardware._widget = 0
    --         end
    --     else
    --         if old_widget ~= new_widget then 
    --             if old_widget ~= 0 then 
    --                 hardware.notify('鼠标离开物体', old_widget)
    --             end 
    --             hardware._widget = new_widget
    --             hardware.notify('鼠标指向物体', new_widget)
    --         end
    --     end
    -- else 
    --     if old_widget ~= 0 then 
    --         hardware.notify('鼠标离开物体', old_widget)
    --         hardware._widget = 0
    --     end
    -- end
end

--[鼠标移动事件]
function hardware.on_mouse_move()
    local x,y = hardware:get_mouse_pos()
    hardware.on_widget_update()
    return hardware.notify('鼠标移动', x, y)
end

--[游戏绘制帧事件]
function hardware.on_update()
    local clock = os.clock()
    local frame = clock - hardware.clock
    hardware.clock = clock 
    hardware.on_widget_update()
    return hardware.notify('界面绘制', frame)
end

local hardware_events = {
    hardware.on_mouse_down,
    hardware.on_mouse_up,
    hardware.on_mouse_right_down,
    hardware.on_mouse_right_up,
    hardware.on_mouse_move,
    hardware.on_mouse_wheeldelta,
    hardware.on_key_down,
    hardware.on_key_up,
    hardware.on_update_window_size,
    hardware.on_update,
}

--[窗口消息事件] 返回true 可以屏蔽硬件事件
function WindowEventCallBack(event_id)
    if hardware_events[event_id] then
        local bool, retval = xpcall(hardware_events[event_id], runtime.error_handle)
        if bool then 
            return retval
        end
    end
    return false
end

---全局事件回调
---@param name string 事件名称
---@param ... any 参数
function hardware.notify(name,...)
    local trigger = hardware.alltriggers[name]
    if not trigger then return end
    local bool = false
    for i = #trigger.actors, 1, -1 do 
        local act = trigger.actors[i]
        bool = bool or act:execute(...)
        if bool == true then 
            break 
        end
    end
    return bool
end

---全局事件监听
---@param name string
function hardware:register(name)
    local trigger = hardware.alltriggers[name]
    if not trigger then 
        trigger = ac.trigger.create(name)
        trigger.remove = function(t)
            for i = #trigger.actors, 1, -1 do 
                local act = trigger.actors[i]
                act:remove()
                hardware.allacts[act] = nil
            end 
            hardware.alltriggers[name] = nil
        end
        hardware.alltriggers[name] = trigger
    end 
    return function (func)
        local act = trigger:add_actor(func)
        act.key = "硬件事件>" .. name
        hardware.allacts[act] = true
        return act
    end
end

hardware.on     = hardware.register
hardware.event  = hardware.register


return hardware